package main_gui;

import calculation.FIRFrequenceSample;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import javax.swing.JFrame;
import my_interface.FrequenceType;
import my_interface.SelectType;

/**
 *
 * @author KieuOanh
 */
public class FrequenceFrame extends JFrame implements SelectType, FrequenceType {

    FIRFrequenceSample firf;
    public final double pi = Math.PI;
    public final double pi2 = 2 * Math.PI;

    public FrequenceFrame(FIRFrequenceSample firf) {
        this.firf = firf;
        setBounds(30, 20, 900, 700);
        setResizable(false);
        setVisible(true);
        setTitle("Frequence Sampling");
    }

    public void setData(FIRFrequenceSample firf) {
        this.firf = firf;
    }

    @Override
    public void paint(Graphics g) {
        g.setColor(Color.LIGHT_GRAY);
        g.fillRect(0, 0, 900, 700);
        g.setColor(Color.WHITE);
        g.fillRect(70, 100, 300, 240);
        g.fillRect(70, 410, 300, 240);
        g.fillRect(510, 100, 300, 240);
        g.fillRect(510, 410, 300, 240);


        /////////////////////////////////////////
        double d = (double) 300 / firf.M;
        double ratio_hn = 180 / (firf.hnMax - firf.hnMin);
        double ratio_Hw = 200 / (firf.HwMax - firf.HwMin);
        double ratio_dB = 215 / firf.dBMax;

        int point0_hn = 100 + (int) (firf.hnMax * 1.2 * ratio_hn);
        int point0_Hw = 400 + (int) (firf.HwMax * 1.2 * ratio_Hw);
        int point0_dB = 435;

        double ratioMaxMin;
        double unit;
        int index;

        double step = (double) 300 / ((firf.M - 1) / 2 + 1);

        g.setColor(Color.BLUE);

        //<editor-fold defaultstate="collapsed" desc="Vẽ Hrk()">
        switch (firf.typeSelect) {
            case LOW_PASS:
            case HIGH_PASS:
                drawHorizon(g, 70, 120);
                drawHorizon(g, 70, 320);
                drawVertical(g, 70 + (int) (firf.wp * 300), 100);
                drawVertical(g, 70 + (int) (firf.ws * 300), 100);

                //
                if (firf.typeSelect == LOW_PASS) {
                    g.drawLine(70, 120, 70 + (int) (firf.wp * 300), 120);
                    g.drawLine(70 + (int) (firf.ws * 300), 320, 370, 320);
                    g.drawLine(70 + (int) (firf.wp * 300), 120, 70 + (int) (firf.ws * 300), 320);
                    int i = 0;
                    while (i * step <= firf.wp * 300 + 5) {
                        g.drawOval(65 + (int) (i * step), 115, 10, 10);
                        i++;
                    }
                    i = 0;
                    while (i * step <= (1 - firf.ws) * 300 + 5) {
                        g.drawOval(65 + (int) (firf.ws * 300 + i * step), 315, 10, 10);
                        i++;
                    }
                } else {
                    g.drawLine(70, 320, 70 + (int) (firf.ws * 300), 320);
                    g.drawLine(70 + (int) (firf.wp * 300), 120, 370, 120);
                    g.drawLine(70 + (int) (firf.ws * 300), 320, 70 + (int) (firf.wp * 300), 120);

                    int i = 0;
                    while (i * step <= firf.ws * 300 + 5) {
                        g.drawOval(65 + (int) (i * step), 315, 10, 10);
                        i++;
                    }
                    i = 0;
                    while (i * step <= (1 - firf.wp) * 300 + 5) {
                        g.drawOval(65 + (int) (firf.wp * 300 + i * step), 115, 10, 10);
                        i++;
                    }
                }

                if (firf.typeFrequence == OPTIMUM_DESIGN) {
                    if (firf.T1 != 0) {
                        drawHorizon(g, 70, 120 + (int) ((1 - firf.T1) * 200));
                        g.setColor(Color.BLACK);
                        g.drawString("" + firf.T1, 50, 120 + (int) ((1 - firf.T1) * 200));
                        g.setColor(Color.BLUE);
                    }
                    if (firf.T2 != 0) {
                        drawHorizon(g, 70, 120 + (int) ((1 - firf.T2) * 200));
                        g.setColor(Color.BLACK);
                        g.drawString("" + firf.T2, 50, 120 + (int) ((1 - firf.T2) * 200));
                        g.setColor(Color.BLUE);
                    }
                }

                if (firf.typeFrequence == 1) {
                    g.drawOval(65 + (int) (300 * (firf.ws - firf.ws * firf.T1 + firf.T1 * firf.wp)), 315 - (int) (firf.T1 * 200), 10, 10);
                    g.drawOval(65 + (int) (300 * (firf.ws - firf.ws * firf.T2 + firf.T2 * firf.wp)), 315 - (int) (firf.T2 * 200), 10, 10);
                }

                break;

            case BAND_PASS:
                drawHorizon(g, 70, 120);
                drawHorizon(g, 70, 320);
                drawVertical(g, 70 + (int) (firf.wp * 300), 100);
                drawVertical(g, 70 + (int) (firf.ws * 300), 100);
                drawVertical(g, 70 + (int) (firf.w2s * 300), 100);
                drawVertical(g, 70 + (int) (firf.w2p * 300), 100);
                g.drawLine(70, 320, 70 + (int) (firf.ws * 300), 320);
                g.drawLine(70 + (int) (firf.wp * 300), 120, 70 + (int) (firf.w2p * 300), 120);
                g.drawLine(70 + (int) (firf.w2s * 300), 320, 370, 320);
                g.drawLine(70 + (int) (firf.ws * 300), 320, 70 + (int) (firf.wp * 300), 120);
                g.drawLine(70 + (int) (firf.w2p * 300), 120, 70 + (int) (firf.w2s * 300), 320);

                if (firf.typeFrequence == OPTIMUM_DESIGN) {
                    if (firf.T1 != 0) {
                        drawHorizon(g, 70, 120 + (int) ((1 - firf.T1) * 200));
                        g.setColor(Color.BLACK);
                        g.drawString("" + round2(firf.T1), 50, 120 + (int) ((1 - firf.T1) * 200));
                        g.setColor(Color.BLUE);
                        g.drawOval(65 + (int) (300 * firf.ws + step), 315 - (int) (firf.T1 * 200), 10, 10);
                        g.drawOval(65 + (int) (300 * firf.w2s - step), 315 - (int) (firf.T1 * 200), 10, 10);
                    }
                    if (firf.T2 != 0) {
                        drawHorizon(g, 70, 120 + (int) ((1 - firf.T2) * 200));
                        g.setColor(Color.BLACK);
                        g.drawString("" + round2(firf.T2), 50, 120 + (int) ((1 - firf.T2) * 200));
                        g.setColor(Color.BLUE);
                        g.drawOval(65 + (int) (300 * firf.wp - step), 315 - (int) (firf.T2 * 200), 10, 10);
                        g.drawOval(65 + (int) (300 * firf.w2p + step), 315 - (int) (firf.T2 * 200), 10, 10);
                    }
                }

                int i = 0;
                while (i * step <= firf.ws * 300 + 5) {
                    g.drawOval(65 + (int) (i * step), 315, 10, 10);
                    i++;
                }
                i = 0;
                while (i * step <= (1 - firf.w2s) * 300 + 5) {
                    g.drawOval(65 + (int) (firf.w2s * 300 + i * step), 315, 10, 10);
                    i++;
                }
                i = 0;
                while (i * step <= (firf.w2p - firf.wp) * 300 + 5) {
                    g.drawOval(65 + (int) (firf.wp * 300 + i * step), 115, 10, 10);
                    i++;
                }
                break;

            case BAND_STOP:
                drawHorizon(g, 70, 120);
                drawHorizon(g, 70, 320);
                drawVertical(g, 70 + (int) (firf.wp * 300), 100);
                drawVertical(g, 70 + (int) (firf.ws * 300), 100);
                drawVertical(g, 70 + (int) (firf.w2s * 300), 100);
                drawVertical(g, 70 + (int) (firf.w2p * 300), 100);
                g.drawLine(70, 120, 70 + (int) (firf.wp * 300), 120);
                g.drawLine(70 + (int) (firf.ws * 300), 320, 70 + (int) (firf.w2s * 300), 320);
                g.drawLine(70 + (int) (firf.w2p * 300), 120, 370, 120);

                g.drawLine(70 + (int) (firf.ws * 300), 320, 70 + (int) (firf.wp * 300), 120);
                g.drawLine(70 + (int) (firf.w2p * 300), 120, 70 + (int) (firf.w2s * 300), 320);

                if (firf.typeFrequence == OPTIMUM_DESIGN) {
                    if (firf.T1 != 0) {
                        drawHorizon(g, 70, 120 + (int) ((1 - firf.T1) * 200));
                        g.setColor(Color.BLACK);
                        g.drawString("" + round2(firf.T1), 50, 120 + (int) ((1 - firf.T1) * 200));
                        g.setColor(Color.BLUE);
                        g.drawOval(65 + (int) (300 * firf.wp + step), 315 - (int) (firf.T1 * 200), 10, 10);
                        g.drawOval(65 + (int) (300 * firf.w2p - step), 315 - (int) (firf.T1 * 200), 10, 10);

                    }
                    if (firf.T2 != 0) {
                        drawHorizon(g, 70, 120 + (int) ((1 - firf.T2) * 200));
                        g.setColor(Color.BLACK);
                        g.drawString("" + round2(firf.T2), 50, 120 + (int) ((1 - firf.T2) * 200));
                        g.setColor(Color.BLUE);
                        g.drawOval(65 + (int) (300 * firf.ws - step), 315 - (int) (firf.T2 * 200), 10, 10);
                        g.drawOval(65 + (int) (300 * firf.w2s + step), 315 - (int) (firf.T2 * 200), 10, 10);
                    }
                }

                i = 0;
                while (i * step <= firf.wp * 300 + 5) {
                    g.drawOval(65 + (int) (i * step), 115, 10, 10);
                    i++;
                }
                i = 0;
                while (i * step <= (1 - firf.w2p) * 300 + 5) {
                    g.drawOval(65 + (int) (firf.w2p * 300 + i * step), 115, 10, 10);
                    i++;
                }
                i = 0;
                while (i * step <= (firf.w2s - firf.ws) * 300 + 5) {
                    g.drawOval(65 + (int) (firf.ws * 300 + i * step), 315, 10, 10);
                    i++;
                }
                break;

        }
        //</editor-fold>
//
        //<editor-fold defaultstate="collapsed" desc="Vẽ hn(n)">
        for (int i = 1; i < firf.M; i++) {
            g.drawLine((int) (i * d) + 510, point0_hn, (int) (i * d) + 510, point0_hn - (int) (firf.hn[i] * ratio_hn));
            g.drawOval((int) (i * d) + 505, point0_hn - (int) (firf.hn[i] * ratio_hn) - 5, 10, 10);
        }


        ratioMaxMin = firf.hnMax / (-firf.hnMin);
        if (ratioMaxMin > 2) {
            unit = round2(-firf.hnMin);
            index = -1;
        } else {
            unit = round2(-firf.hnMin) / 2;
            index = -2;
        }
        while (index < ratioMaxMin + 1) {
            if (index != 0 && point0_hn - (int) (index * unit * ratio_hn) > 410) {
                g.drawString(trim2(unit * index) + "", 40, point0_hn - (int) (index * unit * ratio_hn) + 5);
                g.drawLine(510, point0_hn - (int) (index * unit * ratio_hn), 513, point0_hn - (int) (index * unit * ratio_hn) + 5);
                g.drawLine(370, point0_hn - (int) (index * unit * ratio_hn), 367, point0_hn - (int) (index * unit * ratio_hn) + 5);
            }
            index++;
        }
        for (int i = 0; i < 6; i++) {
            g.drawLine(510 + i * 60, 100, 510 + i * 60, 103);
            g.drawLine(510 + i * 60, 340, 510 + i * 60, 337);
            g.setColor(Color.BLACK);
            g.drawString(firf.M * i / 5 + "", 503 + i * 60, 355);
            g.setColor(Color.BLUE);
        }
        g.drawLine(510, point0_hn, 810, point0_hn);
        //</editor-fold>
//
        //<editor-fold defaultstate="collapsed" desc="Vẽ decibels">
        int xPrevious = 0;
        int yPrevious = (int) (ratio_dB * firf.dB[0]);

        for (int i = 1; i < 300; i++) {
            int yCurrent = (int) (ratio_dB * firf.dB[i]);
            g.drawLine(xPrevious + 510, point0_dB + yPrevious, 510 + i, point0_dB + yCurrent);
            xPrevious = i;
            yPrevious = yCurrent;
        }

        drawVertical(g, 510 + (int) (firf.wp * 300), 410);
        drawVertical(g, 510 + (int) (firf.ws * 300), 410);

        if (firf.typeSelect == BAND_PASS || firf.typeSelect == BAND_STOP) {
            g.setColor(Color.BLACK);
            g.drawString("" + firf.w2p, 503 + (int) (firf.w2p * 300), 665);
            g.drawString("" + firf.w2s, 503 + (int) (firf.w2s * 300), 665);
            g.setColor(Color.BLUE);
            drawVertical(g, 510 + (int) (firf.w2p * 300), 410);
            drawVertical(g, 510 + (int) (firf.w2s * 300), 410);
        }

        drawHorizon(g, 510, point0_dB);
        drawHorizon(g, 510, point0_dB + (int) (firf.As * ratio_dB));
        drawHorizon(g, 510, point0_dB + (int) (firf.dBMin * ratio_dB));
        //</editor-fold>
//      
        //<editor-fold defaultstate="collapsed" desc="Ve Hw()">
        xPrevious = 0;
        yPrevious = (int) (ratio_Hw * firf.Hw[0]);
        for (int i = 1; i < 300; i++) {
            int yCurrent = (int) (ratio_Hw * firf.Hw[i]);
            g.drawLine(xPrevious + 70, point0_Hw - yPrevious, 70 + i, point0_Hw - yCurrent);
            xPrevious = i;
            yPrevious = yCurrent;
        }
        drawHorizon(g, 70, point0_Hw);
        drawHorizon(g, 70, point0_Hw - (int) ratio_Hw);
        drawVertical(g, 70 + (int) (300 * firf.ws), 410);
        drawVertical(g, 70 + (int) (300 * firf.wp), 410);

        if (firf.typeSelect == BAND_PASS || firf.typeSelect == BAND_STOP) {
            drawVertical(g, 70 + (int) (300 * firf.w2s), 410);
            drawVertical(g, 70 + (int) (300 * firf.w2p), 410);
            g.setColor(Color.BLACK);
            g.drawString("" + firf.w2s, 63 + (int) (300 * firf.w2s), 665);
            g.drawString("" + firf.w2p, 63 + (int) (300 * firf.w2p), 665);
        }


        //</editor-fold>
        g.setColor(Color.BLACK);

        //window 1
        g.drawString("Frequence Samples", 150, 90);
        g.drawString("Hr(k)", 10, 220);
        g.drawString("frequence in pi units", 170, 365);
        g.drawRect(70, 100, 300, 240);
        g.drawString("1", 60, 125);
        g.drawString("0", 60, 325);
        g.drawString("0", 65, 355);
        g.drawString("1", 365, 355);
        g.drawString("" + firf.wp, 70 + (int) (firf.wp * 300), 355);
        g.drawString("" + firf.ws, 70 + (int) (firf.ws * 300), 355);
        g.drawString("" + firf.w2s, 70 + (int) (firf.w2s * 300), 355);
        g.drawString("" + firf.w2p, 70 + (int) (firf.w2p * 300), 355);

        //window 2
        g.drawString("Impulse Response", 600, 90);
        g.drawString("h(n)", 450, 220);
        g.drawString("n", 660, 365);
        g.drawRect(70, 410, 300, 240);
        g.drawString("-0.1", 485, point0_hn + 5 + (int) (0.1 * ratio_hn));
        g.drawString("0.1", 485, point0_hn + 5 - (int) (0.1 * ratio_hn));
        g.drawString("0.2", 485, point0_hn + 5 - (int) (0.2 * ratio_hn));
        g.drawLine(510, point0_hn + (int) (0.1 * ratio_hn), 513, point0_hn + (int) (0.1 * ratio_hn));
        g.drawLine(510, point0_hn - (int) (0.1 * ratio_hn), 513, point0_hn - (int) (0.1 * ratio_hn));
        g.drawLine(510, point0_hn - (int) (0.2 * ratio_hn), 513, point0_hn - (int) (0.2 * ratio_hn));

        //window 3
        g.drawString("Amplitude Response", 150, 405);
        g.drawString("|H(w)|", 10, 535);
        g.drawString("frequence in pi units", 170, 685);
        g.drawRect(510, 100, 300, 240);
        g.drawString("0", 60, point0_Hw + 5);
        g.drawString("1", 60, point0_Hw - (int) ratio_Hw + 5);
        g.drawString("0", 67, 665);
        g.drawString("" + firf.ws, 63 + (int) (300 * firf.ws), 665);
        g.drawString("" + firf.wp, 63 + (int) (300 * firf.wp), 665);
        g.drawString("1", 367, 665);

        //window 4
        g.drawString("Magnitude Response in dB", 600, 405);
        g.drawString("Decibels", 430, 550);
        g.drawString("frequence in pi units", 600, 685);
        g.drawRect(510, 410, 300, 240);
        g.drawString("0", 508, 665);
        g.drawString("1", 808, 665);
        g.drawString("" + (int) firf.As, 490, 445 + (int) (firf.As * ratio_dB));
        g.drawString("" + (int) firf.dBMin, 490, 445 + (int) (firf.dBMin * ratio_dB));
        g.drawString("0", 490, 445);
        g.drawString("" + firf.wp, 503 + (int) (firf.wp * 300), 665);
        g.drawString("" + firf.ws, 503 + (int) (firf.ws * 300), 665);

        ////////////////////////////////////////
        g.setFont(new Font("Courier New", Font.BOLD, 20));
        g.drawString("FIR: FREQUENCE SAMPLING DESIGN TECHNIQUE", 220, 60);
    }

    double trim2(double x) {
        return (int) (x * 100) / (double) 100;
    }

    double round2(double x) {
        return (int) (x * 100 + 0.5) / (double) 100;
    }

    void drawHorizon(Graphics g, int startX, int y) {
        for (int i = 0; i < 60; i++) {
            g.drawLine(startX + i * 5, y, startX + 1 + i * 5, y);
        }
    }

    void drawVertical(Graphics g, int x, int startY) {
        for (int i = 0; i < 48; i++) {
            g.drawLine(x, startY + i * 5, x, startY + 1 + i * 5);
        }
    }

    int round(double x) {
        return (int) Math.round(x);
    }
}
